home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / mint / editors / mjovesrc.zoo / re.c < prev    next >
C/C++ Source or Header  |  1992-04-04  |  19KB  |  979 lines

  1. /***************************************************************************
  2.  * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
  3.  * is provided to you without charge, and with no warranty.  You may give  *
  4.  * away copies of JOVE, including sources, provided that this notice is    *
  5.  * included in all the files.                                              *
  6.  ***************************************************************************/
  7.  
  8. /* search package */
  9.  
  10. #include "jove.h"
  11. #include "re.h"
  12. #include "ctype.h"
  13.  
  14. private void
  15.     search proto((int, bool, bool));
  16.  
  17. private int
  18.     do_comp proto((struct RE_block *,int));
  19.  
  20. private char
  21.     searchstr[128];        /* global search string */
  22.  
  23. char    rep_search[128],    /* replace search string */
  24.     rep_str[128];        /* contains replacement string */
  25.  
  26. bool    CaseIgnore = OFF,    /* ignore case? */
  27.     WrapScan = OFF,        /* wrap at end of buffer? */
  28.     UseRE = OFF;        /* use regular expressions */
  29.  
  30. #define cind_cmp(a, b)    (CharUpcase(a) == CharUpcase(b))
  31.  
  32. private int    REpeekc;
  33. private char    *REptr;
  34.  
  35. private int
  36. REgetc()
  37. {
  38.     int    c;
  39.  
  40.     if ((c = REpeekc) != -1)
  41.         REpeekc = -1;
  42.     else if (*REptr)
  43.         c = *REptr++;
  44.     else
  45.         c = '\0';
  46.  
  47.     return c;
  48. }
  49.  
  50. #define STAR     01    /* Match any number of last RE. */
  51. #define AT_BOL    2    /* ^ */
  52. #define AT_EOL    4    /* $ */
  53. #define AT_BOW    6    /* \< */
  54. #define AT_EOW    8    /* \> */
  55. #define OPENP    10    /* \( */
  56. #define CLOSEP    12    /* \) */
  57. #define CURLYB    14    /* \{ */
  58.  
  59. #define NOSTR    14    /* Codes <= NOSTR can't be *'d. */
  60.  
  61. #define ANYC    (NOSTR+2)        /* . */
  62. #define NORMC    (ANYC+2)        /* normal character */
  63. #define CINDC    (NORMC+2)        /* case independent character */
  64. #define ONE_OF    (CINDC+2)        /* [xxx] */
  65. #define NONE_OF    (ONE_OF+2)    /* [^xxx] */
  66. #define BACKREF    (NONE_OF+2)    /* \# */
  67. #define EOP    (BACKREF+2)    /* end of pattern */
  68.  
  69. /* ONE_OF/NONE_OF is represented as a bit vector.
  70.  * These symbols parameterize the representation.
  71.  */
  72.  
  73. #define    BYTESIZE    8
  74. #ifndef MiNT
  75. #define    SETSIZE        (NCHARS / BYTESIZE)
  76. #else
  77. #define    SETSIZE        (0200 / BYTESIZE)
  78. #endif /* MiNT */
  79. #define    SETBYTE(c)    ((c) / BYTESIZE)
  80. #define    SETBIT(c)    (1 << ((c) % BYTESIZE))
  81.  
  82. #define NPAR    10    /* [0-9] - 0th is the entire matched string, i.e. & */
  83. private char    *comp_ptr,
  84.         **alt_p,
  85.         **alt_endp;
  86.  
  87. void
  88. REcompile(pattern, re, re_blk)
  89. char    *pattern;
  90. bool    re;
  91. struct RE_block    *re_blk;
  92. {
  93.     REptr = pattern;
  94.     REpeekc = -1;
  95.     comp_ptr = re_blk->r_compbuf;
  96.     alt_p = re_blk->r_alternates;
  97.     alt_endp = alt_p + NALTS;
  98.     *alt_p++ = comp_ptr;
  99.     re_blk->r_nparens = 0;
  100.     (void) do_comp(re_blk, re ? OKAY_RE : NORM);
  101.     *alt_p = NULL;
  102.  
  103.     re_blk->r_anchored = NO;
  104.     re_blk->r_firstc = '\0';
  105.     /* do a little post processing */
  106.     if (re_blk->r_alternates[1] == NULL) {
  107.         char    *p;
  108.  
  109.         p = re_blk->r_alternates[0];
  110.         for (;;) {
  111.             switch (*p) {
  112.             case OPENP:
  113.             case CLOSEP:
  114.                 p += 2;
  115.                 continue;
  116.  
  117.             case AT_BOW:
  118.             case AT_EOW:
  119.                 p += 1;
  120.                 continue;
  121.  
  122.             case AT_BOL:
  123.                 re_blk->r_anchored = YES;
  124.                 /* don't set firstc -- won't work */
  125.                 break;
  126.  
  127.             case NORMC:
  128.             case CINDC:
  129.                 re_blk->r_firstc = CharUpcase(p[2]);
  130.                 break;
  131.  
  132.             default:
  133.                 break;
  134.             }
  135.             break;
  136.         }
  137.     }
  138. }
  139.  
  140. /* compile the pattern into an internal code */
  141.  
  142. private int
  143. do_comp(re_blk, kind)
  144. struct RE_block    *re_blk;
  145. int    kind;
  146. {
  147.     char    *this_verb,
  148.         *prev_verb,
  149.         *start_p,
  150.         *comp_endp;
  151.     int    parens[NPAR],
  152.         *parenp,
  153.         c,
  154.         ret_code;
  155.  
  156.     parenp = parens;
  157.     this_verb = NULL;
  158.     ret_code = 1;
  159.     comp_endp = &re_blk->r_compbuf[COMPSIZE - 6];
  160.  
  161.     /* wrap the whole expression around (implied) parens */
  162.     if (kind == OKAY_RE) {
  163.         *comp_ptr++ = OPENP;
  164.         *comp_ptr++ = re_blk->r_nparens;
  165.         *parenp++ = re_blk->r_nparens++;
  166.     }
  167.  
  168.     start_p = comp_ptr;
  169.  
  170.     while ((c = REgetc()) != '\0') {
  171.         if (comp_ptr > comp_endp) {
  172. toolong:
  173.             complain("Search string too long/complex.");
  174.         }
  175.         prev_verb = this_verb;
  176.         this_verb = comp_ptr;
  177.  
  178.         if (kind == NORM && strchr(".[*", c) != NULL)
  179.             goto defchar;
  180.         switch (c) {
  181.         case '\\':
  182.             switch (c = REgetc()) {
  183.             case '\0':
  184.                 complain("[Premature end of pattern]");
  185.                 /*NOTREACHED*/
  186.  
  187.             case '{':
  188.                 {
  189.                 char    *wcntp;        /* word count */
  190.  
  191.                 *comp_ptr++ = CURLYB;
  192.                 wcntp = comp_ptr;
  193.                 *comp_ptr++ = 0;
  194.                 for (;;) {
  195.                     int    comp_val;
  196.                     char    *comp_len;
  197.  
  198.                     comp_len = comp_ptr++;
  199.                     comp_val = do_comp(re_blk, IN_CB);
  200.                     *comp_len = comp_ptr - comp_len;
  201.                     (*wcntp) += 1;
  202.                     if (comp_val == 0)
  203.                         break;
  204.                 }
  205.                 break;
  206.                 }
  207.  
  208.             case '}':
  209.                 if (kind != IN_CB)
  210.                     complain("Unexpected \\}.");
  211.                 ret_code = 0;
  212.                 goto outahere;
  213.  
  214.             case '(':
  215.                 if (re_blk->r_nparens >= NPAR)
  216.                     complain("Too many ('s; max is %d.", NPAR);
  217.                 *comp_ptr++ = OPENP;
  218.                 *comp_ptr++ = re_blk->r_nparens;
  219.                 *parenp++ = re_blk->r_nparens++;
  220.                 break;
  221.  
  222.             case ')':
  223.                 if (parenp == parens)
  224.                     complain("Too many )'s.");
  225.                 *comp_ptr++ = CLOSEP;
  226.                 *comp_ptr++ = *--parenp;
  227.                 break;
  228.  
  229.             case '|':
  230.                 if (alt_p >= alt_endp)
  231.                     complain("Too many alternates; max %d.", NALTS);
  232.                 /* close off previous alternate */
  233.                 *comp_ptr++ = CLOSEP;
  234.                 *comp_ptr++ = *--parenp;
  235.                 *comp_ptr++ = EOP;
  236.                 *alt_p++ = comp_ptr;
  237.  
  238.                 /* start a new one */
  239.                 re_blk->r_nparens = 0;
  240.                 *comp_ptr++ = OPENP;
  241.                 *comp_ptr++ = re_blk->r_nparens;
  242.                 *parenp++ = re_blk->r_nparens++;
  243.                 start_p = comp_ptr;
  244.                 break;
  245.  
  246.             case '1':
  247.             case '2':
  248.             case '3':
  249.             case '4':
  250.             case '5':
  251.             case '6':
  252.             case '7':
  253.             case '8':
  254.             case '9':
  255.                 *comp_ptr++ = BACKREF;
  256.                 *comp_ptr++ = c - '0';
  257.                 break;
  258.  
  259.             case '<':
  260.                 *comp_ptr++ = AT_BOW;
  261.                 break;
  262.  
  263.             case '>':
  264.                 *comp_ptr++ = AT_EOW;
  265.                 break;
  266.  
  267.             default:
  268.                 goto defchar;
  269.             }
  270.             break;
  271.  
  272.         case ',':
  273.             if (kind != IN_CB)
  274.                 goto defchar;
  275.             goto outahere;
  276.  
  277.         case '.':
  278.             *comp_ptr++ = ANYC;
  279.             break;
  280.  
  281.         case '^':
  282.             if (comp_ptr == start_p) {
  283.                 *comp_ptr++ = AT_BOL;
  284.                 break;
  285.             }
  286.             goto defchar;
  287.  
  288.         case '$':
  289.             if ((REpeekc = REgetc()) != '\0' && REpeekc != '\\')
  290.                 goto defchar;
  291.             *comp_ptr++ = AT_EOL;
  292.             break;
  293.  
  294.         case '[':
  295.             {
  296.             int    chrcnt;
  297.  
  298.             *comp_ptr++ = ONE_OF;
  299.             if (comp_ptr + SETSIZE >= comp_endp)
  300.                 goto toolong;
  301.             byte_zero(comp_ptr, (size_t) SETSIZE);
  302.             if ((REpeekc = REgetc()) == '^') {
  303.                 *this_verb = NONE_OF;
  304.                 /* Get it for real this time. */
  305.                 (void) REgetc();
  306.             }
  307.             chrcnt = 0;
  308.             while ((c = REgetc()) != ']' && c != '\0') {
  309.                 if (c == '\\') {
  310.                     c = REgetc();
  311.                     if (c == '\0')
  312.                         break;
  313.                 } else if ((REpeekc = REgetc()) == '-') {
  314.                     int    i;
  315.  
  316.                     i = c;
  317.                     (void) REgetc();     /* reread '-' */
  318.                     c = REgetc();
  319.                     if (c == '\0')
  320.                         break;
  321.                     while (i < c) {
  322.                         comp_ptr[SETBYTE(i)] |= SETBIT(i);
  323.                         i += 1;
  324.                     }
  325.                 }
  326.                 comp_ptr[SETBYTE(c)] |= SETBIT(c);
  327.                 chrcnt += 1;
  328.             }
  329.             if (c == '\0')
  330.                 complain("Missing ].");
  331.             if (chrcnt == 0)
  332.                 complain("Empty [].");
  333.             comp_ptr += SETSIZE;
  334.             break;
  335.             }
  336.  
  337.         case '*':
  338.             if (prev_verb == NULL || *prev_verb <= NOSTR || (*prev_verb&STAR)!=0)
  339.                 goto defchar;
  340.  
  341.             if (*prev_verb == NORMC || *prev_verb == CINDC) {
  342.                 char    lastc = comp_ptr[-1];
  343.  
  344.                 /* The * operator applies only to the
  345.                  * previous character.  Since we were
  346.                  * building a string-matching command
  347.                  * (NORMC or CINDC), we must split it
  348.                  * up and work with the last character.
  349.                  *
  350.                  * Note that the STARed versions of these
  351.                  * commands do not operate on strings, and
  352.                  * so do not need or have character counts.
  353.                  */
  354.  
  355.                 if (prev_verb[1] == 1) {
  356.                     /* Only one char in string:
  357.                      * delete old command.
  358.                      */
  359.                     this_verb = prev_verb;
  360.                 } else {
  361.                     /* Several chars in string:
  362.                      * strip off the last.
  363.                      * New verb is derived from old.
  364.                      */
  365.                     prev_verb[1] -= 1;
  366.                     this_verb -= 1;
  367.                     *this_verb = *prev_verb;
  368.                 }
  369.                 comp_ptr = this_verb + 1;
  370.                 *comp_ptr++ = lastc;
  371.             } else {
  372.                 /* This command is just the previous one,
  373.                  * whose verb we will modify.
  374.                  */
  375.                 this_verb = prev_verb;
  376.             }
  377.             *this_verb |= STAR;
  378.             break;
  379.         default:
  380. defchar:
  381.             if ((prev_verb == NULL) ||
  382.                 !(*prev_verb == NORMC || *prev_verb == CINDC)) {
  383.                 /* create new string command */
  384.                 *comp_ptr++ = (CaseIgnore) ? CINDC : NORMC;
  385.                 *comp_ptr++ = 0;
  386.             } else {
  387.                 /* merge this into previous string command */
  388.                 this_verb = prev_verb;
  389.             }
  390.             this_verb[1] +=